﻿using System;
using System.Drawing;

namespace StableDiffusionTools.Imaging
{
    /// <summary>
    /// ColorHSL
    /// </summary>
    public class ColorHSL
    {
        public double H;
        public double S;
        public double L;
        public double A;
        public ColorHSL(double h, double s, double l, double a)
        {
            H = h;
            S = s;
            L = l;
            A = a;
        }
        public ColorHSL(Color c)
        {
            ColorHSL hsl = FromColor(c);
            H = hsl.H;
            S = hsl.S;
            L = hsl.L;
            A = hsl.A;
        }

        public static ColorHSL FromColor(Color color)
        {
            double r = color.R / 255.0;
            double g = color.G / 255.0;
            double b = color.B / 255.0;
            double a = color.A / 255.0;
            double v;
            double m;
            double vm;
            double r2, g2, b2;
            double h, s, l;

            h = 0; // default to black
            s = 0;
            l = 0;
            v = Math.Max(r, g);
            v = Math.Max(v, b);
            m = Math.Min(r, g);
            m = Math.Min(m, b);
            l = (m + v) / 2.0;
            if (l <= 0.0)
            {
                return new ColorHSL(h, s, l, a);
            }
            vm = v - m;
            s = vm;
            if (s > 0.0)
            {
                s /= (l <= 0.5) ? (v + m) : (2.0 - v - m);
            }
            else
            {
                return new ColorHSL(h, s, l, a);
            }
            r2 = (v - r) / vm;
            g2 = (v - g) / vm;
            b2 = (v - b) / vm;
            if (r == v)
            {
                h = (g == m ? 5.0 + b2 : 1.0 - g2);
            }
            else if (g == v)
            {
                h = (b == m ? 1.0 + r2 : 3.0 - b2);
            }
            else
            {
                h = (r == m ? 3.0 + g2 : 5.0 - r2);
            }
            h /= 6.0;

            return new ColorHSL(h, s, l, a);

        }

        public static Color ToColor(double h, double s, double l, double a)
        {
            double v;
            double r, g, b;
            r = l;   // default to gray
            g = l;
            b = l;
            v = (l <= 0.5) ? (l * (1.0 + s)) : (l + s - l * s);
            if (v > 0)
            {
                double m;
                double sv;
                int sextant;
                double fract, vsf, mid1, mid2;

                m = l + l - v;
                sv = (v - m) / v;
                h *= 6.0;
                sextant = (int)h;
                fract = h - sextant;
                vsf = v * sv * fract;
                mid1 = m + vsf;
                mid2 = v - vsf;
                switch (sextant)
                {
                    case 0:
                    r = v;
                    g = mid1;
                    b = m;
                    break;
                    case 1:
                    r = mid2;
                    g = v;
                    b = m;
                    break;
                    case 2:
                    r = m;
                    g = v;
                    b = mid1;
                    break;
                    case 3:
                    r = m;
                    g = mid2;
                    b = v;
                    break;
                    case 4:
                    r = mid1;
                    g = m;
                    b = v;
                    break;
                    case 5:
                    r = v;
                    g = m;
                    b = mid2;
                    break;
                    case 6://TODO test if this is correct
                    r = v;
                    g = mid1;
                    b = m;
                    break;
                }
            }
            return Color.FromArgb(Convert.ToByte(a * 255.0f), Convert.ToByte(r * 255.0f), Convert.ToByte(g * 255.0f), Convert.ToByte(b * 255.0f));
        }

        public Color ToColor()
        {
            return ToColor(H, S, L, A);
        }

        public override string ToString()
        {
            return string.Format("H: {0:0.000} S: {1:0.000} L: {2:0.000} A: {2:0.000}", H, S, L, A);
        }
    }
}
